package forward.Module.Modules.Move;

import forward.Client;
import forward.Module.Module;
import forward.Module.ModuleType;
import forward.Module.Modules.Combat.Killaura;
import forward.UI.ClientNotification;
import forward.Util.*;
import forward.api.Event;
import forward.api.EventHandler;
import forward.api.EventUpdate;
import forward.api.Events.World.*;
import forward.api.Value.Mode;
import forward.api.Value.Option;
import forward.api.eventapi.EventTarget;
import net.minecraft.client.Minecraft;
import net.minecraft.item.ItemSword;
import net.minecraft.network.Packet;
import net.minecraft.network.PacketBuffer;
import net.minecraft.network.play.INetHandlerPlayServer;
import net.minecraft.network.play.client.*;
import net.minecraft.network.play.server.S08PacketPlayerPosLook;
import net.minecraft.network.play.server.S30PacketWindowItems;
import net.minecraft.util.BlockPos;
import net.minecraft.util.EnumFacing;

import java.awt.*;
import java.util.LinkedList;

public class NoSlow extends Module {
    public static Mode<Enum> mode = new Mode("Mode", "Mode", (Enum[]) SlowMode.values(), (Enum) SlowMode.AAC5);
    public static int ticks = 0;
    public TimerUtil timer = new TimerUtil();
    public static Option<Boolean> consume = new Option<Boolean>("consume", "consume", true);
    private MSTimer msTimer = new MSTimer();
    private boolean pendingFlagApplyPacket = false;
    private double lastMotionX = 0.0;
    private double lastMotionY = 0.0;
    private double lastMotionZ = 0.0;
    private MSTimer alertTimer = new MSTimer();
    private boolean sendBuf = false;
    private LinkedList<Packet<INetHandlerPlayServer>> packetBuf = new LinkedList<Packet<INetHandlerPlayServer>>();
    private boolean nextTemp = false;
    private boolean waitC03 = false;
    private boolean lastBlockingStat = false;
    public static int ticks2 = 0;


    public NoSlow() {
        super("NoSlow", new String[]{"noslowdown"}, ModuleType.Move);
        this.setColor(new Color(216, 253, 100).getRGB());
        this.addValues(mode,consume);
    }

    public void onDisable() {
        msTimer.reset();
        pendingFlagApplyPacket = false;
        sendBuf = false;
        packetBuf.clear();
        nextTemp = false;
        waitC03 = false;
    }



    private void sendPacket(MotionUpdateEvent event,
                            boolean sendC07,
                            boolean sendC08,
                            boolean delay,
                            long delayValue,
                            boolean onGround) {
        boolean watchDog = false;

       // C08PacketPlayerBlockPlacement blockPlace = new C08PacketPlayerBlockPlacement(Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem());
      //  C08PacketPlayerBlockPlacement blockMent = new C08PacketPlayerBlockPlacement(new BlockPos(-1, -1, -1), 255, Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem(), 0f, 0f, 0f);
        if (onGround && !Minecraft.getMinecraft().thePlayer.onGround) {
            return;
        }
        if (sendC07 && event.isPre()) {
            //Helper.sendMessage("sendc07");
            if (delay && msTimer.hasTimePassed(delayValue)) {
                mc.getNetHandler().addToSendQueueNoEvent(new C07PacketPlayerDigging(C07PacketPlayerDigging.Action.RELEASE_USE_ITEM, new BlockPos(-1, -1, -1), EnumFacing.DOWN));
            } else if (!delay) {
                mc.getNetHandler().addToSendQueueNoEvent(new C07PacketPlayerDigging(C07PacketPlayerDigging.Action.RELEASE_USE_ITEM, new BlockPos(-1, -1, -1), EnumFacing.DOWN));
            }
        }
        if (sendC08 && !event.isPre()) {
           // Helper.sendMessage("sendc08");
            if (delay && msTimer.hasTimePassed(delayValue) && !watchDog) {
                mc.getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem()));
                msTimer.reset();
            } else if (!delay && !watchDog) {
                mc.getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem()));
            } else if (watchDog) {
                mc.getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(new BlockPos(-1, -1, -1), 255, Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem(), 0f, 0f, 0f));
            }
        }
    }
    private void sendPacket(MotionUpdateEvent event,
                            boolean sendC07,
                            boolean sendC08,
                            boolean delay,
                            long delayValue,
                            boolean onGround,boolean watchDog) {


       // C08PacketPlayerBlockPlacement blockPlace = new C08PacketPlayerBlockPlacement(Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem());
      //  C08PacketPlayerBlockPlacement blockMent = new C08PacketPlayerBlockPlacement(new BlockPos(-1, -1, -1), 255, Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem(), 0f, 0f, 0f);
        if (onGround && !Minecraft.getMinecraft().thePlayer.onGround) {
            return;
        }
        if (sendC07 && event.isPre()) {
            //Helper.sendMessage("sendc07");
            if (delay && msTimer.hasTimePassed(delayValue)) {
                mc.getNetHandler().addToSendQueueNoEvent(new C07PacketPlayerDigging(C07PacketPlayerDigging.Action.RELEASE_USE_ITEM, new BlockPos(-1, -1, -1), EnumFacing.DOWN));
            } else if (!delay) {
                mc.getNetHandler().addToSendQueueNoEvent(new C07PacketPlayerDigging(C07PacketPlayerDigging.Action.RELEASE_USE_ITEM, new BlockPos(-1, -1, -1), EnumFacing.DOWN));
            }
        }
        if (sendC08 && !event.isPre()) {
           // Helper.sendMessage("sendc08");
            if (delay && msTimer.hasTimePassed(delayValue) && !watchDog) {
                mc.getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem()));
                msTimer.reset();
            } else if (!delay && !watchDog) {
                mc.getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem()));
            } else if (watchDog) {
                mc.getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(new BlockPos(-1, -1, -1), 255, Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem(), 0f, 0f, 0f));
            }
        }
    }
    @EventHandler
    public void onPacketReceive(EventPacketReceive e) {
        if ((mode.getValue()==SlowMode.Flux) && e.getPacket() instanceof S30PacketWindowItems && (mc.thePlayer.isUsingItem() || mc.thePlayer.isBlocking())) {
            ticks2 = mc.thePlayer.ticksExisted;
            e.setCancelled(true);
        }
    }
    @EventHandler
    public void onMotion(MotionUpdateEvent event) {
        if (!Client.instance.getModuleManager().getModuleByClass(NoSlow.class).isEnabled()) {
            return;
        }
        if (!PlayerUtil.isMoving()) {
            return;
        }
        if (mode.getValue() == SlowMode.AAC5) {
            if (!event.isPre() && (Minecraft.getMinecraft().thePlayer.isUsingItem() || Minecraft.getMinecraft().thePlayer.isBlocking() || (Killaura.isBlockingStat()))) {
                Minecraft.getMinecraft().getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(new BlockPos(-1, -1, -1), 255, Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem(), 0f, 0f, 0f));
            }
            return;
        }
        if (mode.getValue() != SlowMode.AAC5) {
            if (!Minecraft.getMinecraft().thePlayer.isBlocking() && !Killaura.isBlockingStat()) {
                return;
            }
            if (mode.getValue() == SlowMode.LiquidBounce) {
                sendPacket(event, true, true, false, 0, false);
            } else if (mode.getValue() == SlowMode.AAC) {
                if (Minecraft.getMinecraft().thePlayer.ticksExisted % 3 == 0) {
                    sendPacket(event, true, false, false, 0, false);
                } else if (Minecraft.getMinecraft().thePlayer.ticksExisted % 3 == 1) {
                    sendPacket(event, false, true, false, 0, false);
                }
            } else if (mode.getValue() == SlowMode.NCP) {
                sendPacket(event, true, true, false, 0, false);
               // ClientUtil.sendClientMessage(this.getName() + " Enabled", ClientNotification.Type.SUCCESS);
            }else if (mode.getValue() == SlowMode.Watchdog2) {
                if (event.isPre()) {
                    mc.getNetHandler().addToSendQueueNoEvent(new C07PacketPlayerDigging(C07PacketPlayerDigging.Action.RELEASE_USE_ITEM, BlockPos.ORIGIN, EnumFacing.DOWN));
                } else {
                    mc.getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(new BlockPos(-1, -1, -1), 255, null, 0.0f, 0.0f, 0.0f));
                }
            }else if (mode.getValue() == SlowMode.WatchDog) {
                if (Minecraft.getMinecraft().thePlayer.ticksExisted % 2 == 0) {
                    sendPacket(event, true, false, true, 50, true);
                } else {
                    sendPacket(event, false, true, false, 0, true, true);
                }
            }
            if ((!event.isPre())&&mode.getValue()==SlowMode.Flux){
                if (mc.thePlayer.isUsingItem() || mc.thePlayer.isBlocking()) {
                    int process = Math.min(Math.round(((mc.thePlayer.ticksExisted - ticks2) / 30f * 100)), 100);
                   // ChatUtils.debug("Eating: " + process + "%");
                    mc.getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(new BlockPos(-1, -1, -1), 255,
                            mc.thePlayer.inventory.getCurrentItem(), 0f, 0f, 0f));
                } else {
                    ticks2 = mc.thePlayer.ticksExisted;
                }
            }
        }
    }
    @EventHandler
    public void onUpdate(EventUpdate event){
        if((mode.getValue()==SlowMode.Matrix || mode.getValue()==SlowMode.Vulcan) && (lastBlockingStat || Killaura.isBlockingStat())){
            if(msTimer.hasTimePassed(230) && nextTemp) {
                nextTemp = false;
                mc.getNetHandler().addToSendQueueNoEvent(new C07PacketPlayerDigging(C07PacketPlayerDigging.Action.RELEASE_USE_ITEM, new BlockPos(-1, -1, -1), EnumFacing.DOWN));
                if(!packetBuf.isEmpty()) {
                    boolean canAttack = false;
                    for(int i=0;packetBuf.isEmpty();i++) {
                        Packet packet=packetBuf.get(i);
                        if(packet instanceof C03PacketPlayer) {
                            canAttack = true;
                        }
                        if(!((packet instanceof C02PacketUseEntity || packet instanceof C0APacketAnimation) && !canAttack)) {
                            mc.getNetHandler().addToSendQueueNoEvent(packet);
                        }
                    }
                    packetBuf.clear();
                }
            }
            if(!nextTemp) {
                lastBlockingStat = Killaura.isBlockingStat();
                if (!Killaura.isBlockingStat()) {
                    return;
                }
                mc.getNetHandler().addToSendQueueNoEvent(new C08PacketPlayerBlockPlacement(new BlockPos(-1, -1, -1), 255, Minecraft.getMinecraft().thePlayer.inventory.getCurrentItem(), 0f, 0f, 0f));
                nextTemp = true;
                waitC03 = mode.getValue()==SlowMode.Vulcan;
                msTimer.reset();
            }
        }
    }
    @EventHandler
    public void onPacket(EventPacketSend event){
        Packet packet = event.getPacket();

        if((mode.getValue()==SlowMode.Matrix || mode.getValue()==SlowMode.Vulcan) && nextTemp) {
            if((packet instanceof C07PacketPlayerDigging || packet instanceof C08PacketPlayerBlockPlacement) && Killaura.isBlockingStat()) {
                event.setCancelled(true);
            }else if (packet instanceof C03PacketPlayer || packet instanceof C0APacketAnimation || packet instanceof C0BPacketEntityAction || packet instanceof C02PacketUseEntity || packet instanceof C07PacketPlayerDigging || packet instanceof C08PacketPlayerBlockPlacement) {
                if (mode.getValue()==SlowMode.Vulcan && waitC03 && packet instanceof C03PacketPlayer) {
                    waitC03 = false;
                    return;
                }
                packetBuf.add((Packet<INetHandlerPlayServer>)packet);
                event.setCancelled(true);
            }
        } else if (pendingFlagApplyPacket && packet instanceof C03PacketPlayer.C06PacketPlayerPosLook) {
            pendingFlagApplyPacket = false;

        }
    }





    private boolean isBlocking() {
        return isHoldingSword() && Minecraft.getMinecraft().thePlayer.isBlocking();
    }


    public enum SlowMode {
        AAC5, AAC, LiquidBounce, Matrix, NCP, Vanilla, Vulcan, WatchDog, Watchdog2,Flux;
    }

    public static boolean isHoldingSword() {
        return Minecraft.getMinecraft().thePlayer.getCurrentEquippedItem() != null && Minecraft.getMinecraft().thePlayer.getCurrentEquippedItem().getItem() instanceof ItemSword;
    }

    public static boolean isOnGround(double height) {
        Minecraft.getMinecraft().getMinecraft().getMinecraft();
        if (!Minecraft.getMinecraft().theWorld.getCollidingBoundingBoxes(Minecraft.getMinecraft().thePlayer, Minecraft.getMinecraft().thePlayer.getEntityBoundingBox().offset(0.0D, -height, 0.0D)).isEmpty()) {
            return true;
        }
        return false;
    }
}


